package com.gp.shaw.netty.nio.im;

import com.gp.shaw.netty.nio.im.model.IMMsg;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by asus on 2018/11/1.
 */
public class IMServer {
    private final static int DEFAULT_PROT=8080;

    private int port= DEFAULT_PROT;

    private ServerSocketChannel serverSocketChannel = null;

    //创建选择器（Selector/Reactor）
    private Selector selector = null;
    //用户管理者
    private static UserManager userManager = new UserManager();;

    //消息队列
    private static LinkedBlockingQueue<IMMsg> msgQueue = new LinkedBlockingQueue<>();

    //消息发送线程
    private SendThread sendThread = null;

    public IMServer(int port){
        this.port = port;
    }
    public void start(){
        try {
            System.out.println("IM服务启动，端口号："+port);
//            serverSocket = new ServerSocket(port);
            if(serverSocketChannel == null) {
                serverSocketChannel = ServerSocketChannel.open();
                serverSocketChannel.bind(new InetSocketAddress(port));
            }

            if(selector==null){
                selector = Selector.open();
            }

            serverSocketChannel.configureBlocking(false);
            //注册连接接收事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            //开启发送轮询线程
            sendThread = new SendThread(msgQueue,userManager);
            sendThread.start();
            //消息接收线程
            while(true){
//                Socket socket = serverSocket.accept();
//                executorService.execute(new IMHandler(socket,userManager,msgQueue));
               int num = selector.select();
               //如果num大于0则表示有准备好的channel
                if(num==0){
                    continue;
                }
                Set<SelectionKey> keys = selector.selectedKeys();
                if(keys==null||keys.size()==0){
                    continue;
                }
                Iterator<SelectionKey> keyIterator = keys.iterator();
                while(keyIterator.hasNext()){
                    SelectionKey key = keyIterator.next();
                    keyIterator.remove();
                    if(key.isValid() &&key.isAcceptable()){
                        try {
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector,SelectionKey.OP_READ|SelectionKey.OP_WRITE);
                        } catch (ClosedChannelException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }else if(key.isReadable()){
                        IMHandler handler = new IMHandler((SocketChannel) key.channel(),userManager,msgQueue);
                        handler.doRead();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close();
        }
    }



    public void close(){
        if(serverSocketChannel!=null) {
            try {
                serverSocketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            serverSocketChannel = null;
        }

        if(selector!=null) {
            try {
                selector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            selector = null;
        }
    }
}
